#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#define BUFFER_SIZE 10

typedef struct MyFILE
{
  char _buffer[BUFFER_SIZE];
  int _end;//指向最后一个数据后面一个也可以当作是size
  int _fd;//文件描述符
}file;

file* myfopen(const char*filename,const char* mode)
{
  assert(filename);
  assert(mode);
  file *newFILE=(file*)calloc(sizeof(MyFILE),1);
  if(newFILE==NULL)
  {
    printf("open file!\n");
  }
  //memset(NewFILE,0,sizeof(MyFILE));
  file*fp=newFILE; 
  if(strcmp("r",mode)==0)
  {
    fp->_fd= open(filename,O_RDONLY,0666);
  }
  else if(strcmp("r+",mode)==0)
  {
    fp->_fd=open(filename,O_RDWR,0666);
  }
  else if(strcmp("w",mode)==0)
  {
    fp->_fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0666);
  }
  else if(strcmp("w+",mode)==0)
  {
    fp->_fd=open(filename,O_RDWR|O_TRUNC|O_CREAT,0666);
  }
  else if(strcmp("a",mode)==0)
  {
    fp->_fd=open(filename,O_WRONLY|O_APPEND|O_CREAT,0666);
  }
  else if(strcmp("a+",mode)==0)
  {
    fp->_fd=open(filename,O_RDWR|O_APPEND|O_CREAT,0666);
  }
  else
  {
    free(fp);
    return NULL;
  }
  return fp;
}

void myfflush(file*stream)
{
  assert(stream);
  if(stream->_end==0)
  {
    return;
  }
  write(stream->_fd,stream->_buffer,stream->_end);//载入内核缓冲区
  syncfs(stream->_fd);//载入磁盘
  stream->_end=0;
  memset(stream->_buffer,0,sizeof(stream->_buffer));
}

void myfputs(const char*str,file*stream)
{
  file*fp=stream;
  if(fp->_end+strlen(str)>=BUFFER_SIZE)//满刷新判断,这是所以文件都需要满足的
  {
    //如果满了直接就载入内存了
    myfflush(fp);
    fp->_end=0;
    while(strlen(str)>=BUFFER_SIZE)//如果刷新了之后还是满了的话
    {
      memcpy(fp->_buffer,str,BUFFER_SIZE-1);
      fp->_end=BUFFER_SIZE-1;
      stream->_buffer[fp->_end]='\0';
      str=str+BUFFER_SIZE-1;
      myfflush(fp);
    }
    //不再满了之后
    strcpy(fp->_buffer,str);
    fp->_end=strlen(str);
    //debug
    
    //printf("%s\n",fp->_buffer);
  }
  else{//不满则直接放入缓冲区
    strcpy(fp->_buffer+fp->_end,str); 
    fp->_end+=strlen(str);
  }


  if(fp->_fd==1||fp->_fd==2)//如果是标准输出和标准错误时的刷新策略
  { 
  
    //标准输出和标准错误
    for(int i=strlen(str)-1;i>=0;i--)
    {//从后往前寻找如果有\n就刷新
      if(str[i]=='\n')
      {
        write(fp->_fd,fp->_buffer,i+1);
        myfflush(fp);
        if(str[i+1]!='\0')//把\n后面没有刷新的重新放入缓冲区
        {
          strcpy(fp->_buffer,str+i+1);
          fp->_end=strlen(fp->_buffer);
        }
        return;
      }
    }
  }
}

void myfclose(file *stream)
{
  myfflush(stream);
  close(stream->_fd);
}
int main()
{
  file *fp=myfopen("tmp.txt","w");
  printf("fp :%d\n",fp->_fd);
  char str[]="12345678912345678910\n";
  myfputs(str,fp);
  myfclose(fp);
  return 0;
}
